﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using The_Square_Saga.Utils;

namespace The_Square_Saga.Levels
{
    /// <summary>Tipos de tiles</summary>
    public enum TileType {
        /// <summary>Tile vazio</summary>
        EMPTY,
        /// <summary>Tile que bloqueia por todos os lados</summary>
        PLATAFORM,
        /// <summary>Tile que bloqueia apenas por cima</summary>
        PASSABLE_PLATAFORM,
        /// <summary>Tile inclinado</summary>
        SLOPED,
        /// <summary>Tile com morte instantanea</summary>
        DEATH,
        /// <summary>Tile que representa um buraco </summary>
        HOLE,
        /// <summary>Tile que representa a escada</summary>
        LADDER,
        /// <summary>Tile que representa a escada</summary>
        FIRST_STEP_LADDER,
    }

    class Tile
    {
        public TileType type;
    }

    class SlopedTile : Tile
    {
        /// <summary>Altura esquerda da borda</summary>
        int y1;

        /// <summary>Altura direita da borda</summary>
        int y2;

        /// <summary>
        /// Seta a altura das bordas do tile
        /// </summary>
        /// <param name="y1">Borda esquerda</param>
        /// <param name="y2">Borda direita</param>
        public void setBordersValues(int y1, int y2)
        {
            this.y1 = y1;
            this.y2 = y2;
        }

        public int calculateYValueForXPosition(Point tilePosition, Rectangle geCollisionRect)
        {
            Rectangle tileRect = new Rectangle(tilePosition.X * GameConfig.TILE_SIZE, tilePosition.Y * GameConfig.TILE_SIZE,
                GameConfig.TILE_SIZE - 1, GameConfig.TILE_SIZE - 1);

            // parametros a b da equação da reta
            int a = ((tileRect.Top + y2) - (tileRect.Top + y1)) / (tileRect.Right - tileRect.Left);
            int b = (tileRect.Top + y1) - ((((tileRect.Top + y2) - (tileRect.Top + y1)) / (tileRect.Right - tileRect.Left)) * tileRect.Left);

            geCollisionRect.Width--;

            // retorna o valor y da equação da reta
            return (a * geCollisionRect.Center.X) + b;
        }
    }

    class Tileset
    {
        /// <summary>Tiles do tileset</summary>
        Tile[] tiles;

        /// <summary>Textura do tileset</summary>
        public Texture2D texture;

        /// <summary>Margem esquerda e superior do tile no tileset</summary>
        public int marginTile;

        public int columns;

        /// <summary>
        /// Cria um tileset com um total de tiles,
        /// e seta todos os tiles como o tipo plataforma
        /// </summary>
        /// <param name="totalTiles">Total de tiles no tileset</param>
        /// <param name="totalColumns">Total de colunas no tileset</param>
        /// <param name="marginTile">Margem esquerda e superior do tile no tileset</param>
        public Tileset(int totalTiles, int totalColumns, int marginTile)
        {
            this.columns = totalColumns;
            this.marginTile = marginTile;

            tiles = new Tile[totalTiles];
            for(int i = 0; i < totalTiles; i++)
            {
                tiles[i] = new Tile();
                tiles[i].type = TileType.PLATAFORM;
            }
        }

        public void loadTexture(string nameTexture, ContentManager content)
        {
            texture = content.Load<Texture2D>(nameTexture);
        }
        
        /// <summary>
        /// Retorna o tipo de um tile
        /// </summary>
        /// <param name="id">Id do tile</param>
        public TileType getTileType(int id)
        {
            if (id == 0)
                return TileType.EMPTY;
            else
            {
                id--;
                return tiles[id].type;
            }
        }

        public void setEmptyTile(int id)
        {
            id--;
            if ((id) < tiles.Length)
                tiles[id].type = TileType.EMPTY;
        }

        public void setEmptyTile(int fromId, int toId)
        {
            fromId--;
            toId--;

            for (int i = fromId; i < (toId + 1); i++)
            {
                if ((i) < tiles.Length)
                    tiles[i].type = TileType.EMPTY;
            }
        }

        public void setPlataformTile(int id)
        {
            id--;
            if ((id) < tiles.Length)
                tiles[id].type = TileType.PLATAFORM;
        }

        public void setPassablePlataformTile(int id)
        {
            id--;
            if ((id) < tiles.Length)
                tiles[id].type = TileType.PASSABLE_PLATAFORM;
        }

        /// <summary>
        /// Seta um tile como inclinado.
        /// </summary>
        /// <param name="id">Id do tile</param>
        /// <param name="y1">Altura da borda esquerda</param>
        /// <param name="y2">Altura da borda direita</param>
        public void setSlopedTile(int id, int y1, int y2)
        {
            id--;
            if ((id) < tiles.Length)
            {
                SlopedTile slopedTile = new SlopedTile();
                slopedTile.type = TileType.SLOPED;
                slopedTile.setBordersValues(y1, y2);
                tiles[id] = slopedTile;
            }
        }

        public void setHoleTile(int id)
        {
            id--;
            if ((id) < tiles.Length)
                tiles[id].type = TileType.HOLE;
        }

        public void setLadderTile(int id)
        {
            id--;
            if ((id) < tiles.Length)
                tiles[id].type = TileType.LADDER;
        }

        public void setFisrstStepLadderTile(int id)
        {
            id--;
            if ((id) < tiles.Length)
                tiles[id].type = TileType.FIRST_STEP_LADDER;
        }

        public void setDeathTile(int id)
        {
            id--;
            if ((id) < tiles.Length)
                tiles[id].type = TileType.DEATH;
        }

        public int? getYValueForSlopedTile(int id, Point tilePosition, Rectangle geCollisionRect)
        {
            id--;
            SlopedTile slopedTile = tiles[id] as SlopedTile;
            if (slopedTile != null)
                return slopedTile.calculateYValueForXPosition(tilePosition, geCollisionRect);
            else
                return null;
        }
    }
}
